; docformat = 'rst'
;
; NAME:
;       MrDrawWidget__Define
;
;*****************************************************************************************
;   Copyright (c) 2014, University of New Hampshire                                      ;
;   All rights reserved.                                                                 ;
;                                                                                        ;
;   Redistribution and use in source and binary forms, with or without modification,     ;
;   are permitted provided that the following conditions are met:                        ;
;                                                                                        ;
;       * Redistributions of source code must retain the above copyright notice,         ;
;         this list of conditions and the following disclaimer.                          ;
;       * Redistributions in binary form must reproduce the above copyright notice,      ;
;         this list of conditions and the following disclaimer in the documentation      ;
;         and/or other materials provided with the distribution.                         ;
;       * Neither the name of the University of New Hampshire nor the names of its       ;
;         contributors may be used to endorse or promote products derived from this      ;
;         software without specific prior written permission.                            ;
;                                                                                        ;
;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY  ;
;   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ;
;   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT  ;
;   SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       ;
;   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ;
;   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR   ;
;   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN     ;
;   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN   ;
;   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH  ;
;   DAMAGE.                                                                              ;
;*****************************************************************************************
;
; PURPOSE
;+
;   The purpose of this class is to provide an object wrapper for the basic widget
;   properties available through Widget_Control and Widget_Info.
;
;   UVALUE:
;       When the UVALUE is set, any previously stored UVALUE will be overwritten. Any
;       pointers or objects that are part of the UVALUE must be freed or destroyed by
;       before over-writing to prevent memory leakage.
;
;   EVENT_PRO & EVENT_FUNC:
;       The Widget_Control procedure should not be used to set the EVENT_PRO or EVENT_FUNC
;       keywords to any subclasses of MrWidgetAtom__Define. Instead, use the SetProperty
;       method. This ensures proper event handling under all circumstances.
;
; :Author:
;   Matthew Argall::
;       University of New Hampshire
;       Morse Hall, Room 113
;       8 College Rd.
;       Durham, NH, 03824
;       matthew.argall@wildcats.unh.edu
;
; :History:
;	Modification History::
;       2014/03/17  -   Written by Matthew Argall
;       2014/09/13  -   Added the EVENT_PRO, EVENT_FUNC, and EVENT_OBJ properties. Removed
;                           the EVENT_HANLDER and FUNC_EVENT_HANDLERS properties. - MRA
;-
;*****************************************************************************************
;+
;   General event handler for the MrWidget object classes. Its purpose is to forward
;   the different events generated by the XManager to their respective event handling
;   methods.
;
;   Unless the /FUNC_HANDLERS keyword is set, any keyword that turns events ON or OFF
;   have their events passed here. This method is the EVENT_PRO for all such keywords.
;   The EVENT_PRO keyword cannot be set as in a normal widget. From here, events are
;   forwarded to their event handling procedures or methods.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;
; :Keywords:
;       STATUS:             out, optional, type=integer
;                           Named variable into which the exit status is returned.
;                               Possible values include::
;                                   -1  -   Error occurred
;                                    1  -   Event handling complete (EVENT_PRO/EVENT_FUNC given)
;                                    0  -   Event handling incomplete
;-
pro MrWidgetAtom_Event_Pro, event, $
STATUS=status
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        status = -1
        void = cgErrorMsg()
        return
    endif
    
    status = 0

    ;Get the object reference
    widget_control, event.id, GET_UVALUE=ORef
    ORef -> GetProperty, EVENT_OBJ=event_obj, EVENT_PRO=event_pro
    tf_obj_handler = obj_valid(event_obj)
    
;---------------------------------------------------------------------
;Forward All Events? /////////////////////////////////////////////////
;---------------------------------------------------------------------
    ;Object event handling class?
    if event_pro ne '' then begin
        if tf_obj_handler $
            then Call_Method, event_pro, event_obj, event $
            else Call_Procedure, event_pro, event
        
        status = 1
        return
    endif
        
;---------------------------------------------------------------------
;Set Object Properties ///////////////////////////////////////////////
;---------------------------------------------------------------------
    
    ;Handle tracking events
    ;   - The one event-type common to all widgets.
    ;   - Callback procedure or method?
    case size(event, /SNAME) of
        'TRACKING_EVENTS': begin
            ORef -> GetProperty, TRACKING_HANDLER=tracking_eh
            if tracking_eh ne '' then begin
                if tf_obj_handler $
                    then Call_Method, tracking_eh, event_obj, event $
                    else Call_Procedure, tracking_eh, event
            endif
        endcase
        
        else: ;Do nothing
    endcase
end


;+
;   Event handling function for Event_Func.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;
; :Returns:
;       RESULTS:            The result returned by the forwarding method. Returns zero (0)
;                               if the event type is unknown or an error occurred.
;-
function MrWidgetAtom_Event_Func, event, $
STATUS=status
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        status = -1
        void = cgErrorMsg()
        return, 0
    endif
    
    status = 0
    
    ;Get the object reference.
    widget_control, event.id, GET_UVALUE=ORef
    ORef -> GetProperty, EVENT_OBJ=event_obj, EVENT_FUNC=event_func
    tf_obj_handler = obj_valid(event_obj)
    
;---------------------------------------------------------------------
;Callback Object /////////////////////////////////////////////////////
;---------------------------------------------------------------------
    ;If an object event handler exists, then call it and return
    if event_func ne '' then begin
        if tf_obj_handler $
            then result = Call_Method('EVENT_FUNC', event_obj, event) $
            else result = Call_Function(event_func, event)
        
        status = 1
        return, result
    endif
    
;---------------------------------------------------------------------
;Callback Func/Method ////////////////////////////////////////////////
;---------------------------------------------------------------------
    ;Forward tracking events -- The one event-type common to all widgets.
    case size(event, /SNAME) of
        'TRACKING_EVENTS': begin
            ORef -> GetProperty, TRACKING_HANDLER=tracking_eh
            if tracking_eh ne '' then begin
                if tf_obj_handler $
                    then result = Call_Method(tracking_eh, event_obj, event) $
                    else result = Call_Function(tracking_eh, event)
            endif
        endcase
        
        else: result = 0
    endcase
    
    ;Make sure the output is defined.
    if n_elements(result) eq 0 then result = 0
    
    return, result
end


;+
;   Event handling function for Func_Get_Value.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;
; :Returns:
;       RESULTS:            The result returned by the forwarding method. Returns zero (0)
;                               if no forwarding method exists or if an error occurred.
;-
function MrWidgetAtom_Func_Get_Value, event
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return, 0
    endif
    
    ;Get the object reference and the KILL_NOTIFY method.
    widget_control, event.id, GET_UVALUE=oRef
    oRef -> GetProperty, HANDLER_FUNC_GET_VALUE=func_get_eh
    
    ;Forward the event to the proper object method.
    case size(func_get_eh, /TNAME) of
        'OBJREF': result = Call_Method(func_get_eh.method, func_get_eh.object, event)
        'STRING': if func_get_eh ne '' then result = Call_Function(func_get_eh, event)
    endcase
    
    ;Make sure the output is defined.
    if n_elements(result) eq 0 then result = 0
    
    ;Return the results.
    return, result
end


;+
;   Event handling method for Kill_Notify Events.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
pro MrWidgetAtom_Kill_Notify, id
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif

    ;Get the object reference and the KILL_NOTIFY method.
    widget_control, id, GET_UVALUE=ObjRef
    if obj_valid(ObjRef) eq 0 then return
    
    ;Get the kill notify handler
    ObjRef -> GetProperty, HANDLER_KILL_NOTIFY=kill_notify_eh

    ;Forward the event to the proper procedure.
    case size(kill_notify_eh, /TNAME) of
        'STRUCT': Call_Method, kill_notify_eh.method, kill_notify_eh.object, id
        'STRING': if kill_notify_eh ne '' then Call_Procedure, kill_notify_eh, id
    endcase
end


;+
;   Event handling method for Notify_Realize Events.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
pro MrWidgetAtom_Notify_Realize, id
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif
    
    ;Get the object reference and the NOTIFY_REALIZE method.
    widget_control, id, GET_UVALUE=ObjRef
    ObjRef -> GetProperty, HANDLER_NOTIFY_REALIZE=notify_realize_eh

    ;Forward the event to the proper procedure.
    case size(notify_realize_eh, /TNAME) of
        'STRUCT': Call_Method, notify_realize_eh.method, notify_realize_eh.object, id
        'STRING': if notify_realize_eh ne '' then Call_Procedure, notify_realize_eh, id
    endcase
end


;+
;   Event handling method for Pro_Set_Value.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
pro MrWidgetAtom_Pro_Set_Value, event
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif
    
    ;Get the object reference and the NOTIFY_REALIZE method.
    widget_control, event.id, GET_UVALUE=oRef
    oRef -> GetProperty, HANDLER_PRO_SET_VALUE=pro_set_eh
    
    ;Forward the event to the proper procedure.
    case size(psvh, /TNAME) of
        'OBJREF': Call_Method, pro_set_eh.method, pro_set_eh.object, event
        'STRING': if pro_set_eh ne '' then Call_Procedure, pro_set_eh, event
    endcase
end


;+
;   The purpose of this method is to destroy the widget and, consequently, the object.
;-
pro MrWidgetAtom::Destroy
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif
    
    ;Destroy the widget. This will trigger a Kill_Notify event. The Kill_Notify
    ;callback is, in turn, setup to destroy the object.
    if widget_info(self._id, /VALID_ID) $
        then widget_control, self._id, /DESTROY $
        else obj_destroy, self
end


;+
;   General event handling function.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;
; :Returns:
;       VALUE:          The value stored in the VALUE property of `EVENT`.ID
;-
function MrWidgetAtom::Event_Func, event
    ;Nothing to return.
    return, 0
end


;+
;   General event handling procedure.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
function MrWidgetAtom::Event_Pro, event
    ;Nothing to do.
end


;+
;   Event handling function for Func_Get_Value.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;
; :Returns:
;       VALUE:          The value stored in the VALUE property of `EVENT`.ID
;-
function MrWidgetAtom::Func_Get_Value, event
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return, 0
    endif
    
    ;Get the value.
    widget_control, event.id, GET_VALUE=value
    
    ;Return the results.
    return, value
end


;+
;   Event handling function for Func_Get_Value.
;
; :Private:
;
; :Params:
;       UNAME:              in, optional, type=string/strarr
;                           User-names of the widgets for which the widget ID is to be
;                               returned.
;
; :Returns:
;       WIDS:               The widget IDs of the widgets with name `UNAME`. Returns zero
;                               if the UNAME is not found.
;-
function MrWidgetAtom::Find_By_UName, uname
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return, 0
    endif
    
    ;Return a single name?
    nNames = n_elements(uname)
    if nNames eq 1 then return, widget_info(self._id, FIND_BY_UNAME=uname)
    
    ;Multiple names
    ids = lonarr(nNames)
    for i = 0, nNames - 1 do ids[i] = widget_info(self._id, FIND_BY_UNAME=uname[i])
    
    ;Return the results.
    return, ids
end


;+
;   Get object properties. Complementary to retrieving object properties, most of the
;   options accessible via Widget_Control and Widget_Info are accessible through this
;   method.
;
; :Keywords:
;       ACTIVE:             out, optional, type=boolean
;                           True (1, one) if at least one realized, managed, top-level
;                               widget on the screen. False (0) otherwise.
;       ALL_CHILDREN:       out, optional, type=integer=intarr
;                           Widget IDs of immediate child widgets. 0 is returned if there
;                               are no children.
;       CHILD:              out, optional, type=integer
;                           First child of the widget.
;       DISPLAY:            out, optional, type=boolean
;                           Returns true (1, one) if the environment is capable of
;                               displaying widgets and false (0) otherwise.
;       FIND_BY_NAME:       in, out, optional, type=string/integer
;                           Upon input, a variable containing the name of the widget whose
;                               ID is to be found. Upon output, the ID of the widget.
;       FONT_NAME:          out, optional, type=string
;                           Name of the font begin used by the widget.
;       GEOMETRY:           out, optional, type=structure
;                           Offset and size information of the widget. See Widget_Info
;                               for more details.
;       MANAGED:            out, optional, type=boolean
;                           Returns true (1, one) if the widget is managed, false (0)
;                               otherwise.
;       MAP:                out, optional, type=boolean
;                           Returns 1 (one) of the widget is mapped and visible on
;                               the screen. Returns 0 if it is unmapped and invisible.
;       N_CHILDREN:         out, optional, type=integer
;                           Number of immediate children.
;       EVENT_HANDLER:      out, optional, type=struct/string
;                           This keyword replaced the EVENT_PRO and EVENT_FUNC
;                               keywords in Widget_Control and other widget functions.
;                               If a string is provided, it is the name of a procedure
;                               to be called when events are generated. If a structure
;                               is provided, it must have "object" and "method" fields
;                               describing the procedure method to be used as an event
;                               handler.
;       FUNC_HANDLERS:      out, optional, type=boolean
;                           If set, then `EVENT_HANDLER` (if a string) and all events
;                               handlers whose events are passed through it, are functions,
;                               not procedures.
;       FUNC_GET_VALUE:     out, optional, type=string/structure, default=''
;                           A string specifying the name of a function to be called
;                               when the value of the base is changed. Alternatively,
;                               a structure of the form::
;                                   FUNC_GET_VALUE = {object: objRef, $
;                                                     method: 'Event_Handler'}
;                               where "objRef" is a valid object reference and
;                               "Event_Handler" is a string containing the name of a
;                               function method to be used to handle events.
;       KILL_NOTIFY:        out, optional, type=string/structure, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget dies (see `FUNC_GET_VALUE`).
;       MAP:                out, optional, type=boolean, default=1
;                           Set to 0 to make the widget and its children invisible. Set
;                               to 1 (one) to make them visible again. The widget must
;                               be realized first.
;       NAME:               out, optional, type=string
;                           Widget type name of the widget.
;       NO_COPY:            out, optional, type=boolean, default=0
;                           If set, `UVALUE` will be taken directly from the widget,
;                               leaving the property undefined. This prevents multiple
;                               copies of the data from existing.
;       NOTIFY_REALIZE:     out, optional, type=string/structure, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget is realized (see `FUNC_GET_VALUE`).
;       PARENT:             out, optional, type=long
;                           Widget ID of the parent widget.
;       PRO_GET_VALUE:      out, optional, type=string, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget's value is retrieved (see `FUNC_GET_VALUE`).
;       REALIZED:           out, optional, type=0
;                           Returns 1 (one) if the widget is realized and 0 otherwise.
;       SIBLING:            out, optional, type=long
;                           Widget ID if the first sibling. 0 is returned if this is the
;                               widget is the last sibling.
;       SENSITIVE:          out, optional, type=boolean
;                           If set, the widget will be sensitive and can receive input.
;                               When insensitive, a widget appears greyed out and does
;                               not generate events.
;       STRING_SIZE:        in, out, optional, type=intarr(2)
;                           Upon input, a variable containing the string or [string, font]
;                               to be measured. Upon output, the string's [width, height].
;       SYSTEM_COLOR:       out, optional, type=bytarr(3,25)
;                           RGB values for the 25 display elements.
;       TYPE:               out, optional, type=integer
;                           Type code of the widget.
;       TRACKING_EVENTS:    out, optional, type=boolean
;                           If set, tracking events are enabled.
;       UNAME:              out, optional, type=string, default=''
;                           User-defined name of the widget.
;       UVALUE:             out, optional, type=any
;                           User-defined value of any type to be stored in the object.
;       UDPATE:             out, optional, type=boolean
;                           Enables and disables the widget updates. See Widget_Control
;                               for details.
;       UNITS:              out, optional, type=integer, default=0
;                           The units for measurments. Choices are::
;                               0 - Pixels
;                               1 - Inches
;                               2 - Centimeters
;       VALID_ID:           out, optional, type=boolean
;                           Returns 1 (one) if the widget ID is valid, 0 otherwise.
;       VERSION:            out, optional, type=structure
;                           Information about the widget implementation.
;       VISIBLE:            out, optional, type=boolean
;                           Returns 1 (one) if the widget and its ancestors have been
;                               realized and are mapped, and 0 otherwise.
;       WINDOW_SIZE:        out, optional, type=intarr(2)
;                           [height, width] if the top level base (`UNITS`)
;       WINDOW_OFFSET:      out, optional, type=intarr(2)
;                           [x,y] offset of the top level base (`UNITS`)
;-
pro MrWidgetAtom::GetProperty, $
 ID=id, $
 
 ;Widget_Info Options
 ACTIVE=active, $
 ALL_CHILDREN=all_children, $
 CHILD=child, $
 DISPLAY=display, $
 FONT_NAME=font_name, $
 GEOMETRY=geometry, $
 MANAGED=managed, $
 MAP=map, $
 N_CHILDREN=n_children, $
 NAME=name, $
 NO_COPY=no_copy, $
 PARENT=parent, $
 REALIZED=realized, $
 SENSITIVE=sensitive, $
 SIBLING=sibling, $
 STRING_SIZE=string_size, $
 SYSTEM_COLORS=system_colors, $
 TYPE=type, $
 UNAME=uname, $
 UNITS=units, $
 UPDATE=update, $
 UVALUE=uvalue, $
 VALID_ID=valid_id, $
 VERSION=version, $
 VISIBLE=visible, $
 
 ;Widget_Control Options
 WINDOW_OFFSET = window_offset, $
 WINDOW_SIZE   = window_size, $
 
 ;Events On or Off?
 TRACKING_EVENTS   = tracking_events, $
 KBRD_FOCUS_EVENTS = kbrd_focus_events, $
 
 ;Callback Pro/Func Event Handlers
 EVENT_FUNC     = event_func, $
 EVENT_PRO      = event_pro, $
 EVENT_OBJ      = event_obj, $
 FUNC_GET_VALUE = func_get_value, $
 KILL_NOTIFY    = kill_notify, $
 NOTIFY_REALIZE = notify_realize, $
 PRO_GET_VALUE  = pro_get_value, $
 
 ;Callback Object Handlers
 HANDLER_FUNC_GET_VALUE = func_get_value_handler, $
 HANDLER_KILL_NOTIFY    = kill_notify_handler, $
 HANDLER_NOTIFY_REALIZE = notify_realize_handler, $
 HANDLER_PRO_SET_VALUE  = pro_set_value_handler, $
 TRACKING_HANDLER       = tracking_handler
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif

    valid_id = widget_info(self._id, /VALID_ID)
    if valid_id eq 0 then return

    if arg_present(id)     then id =  self._id
    if arg_present(uvalue) then begin
        if keyword_set(no_copy) $
            then uvalue = temporary(*self.uvalue) $
            else uvalue = *self.uvalue
    endif
    
;---------------------------------------------------------------------
;Widget_Info & Widget_Control Options ////////////////////////////////
;---------------------------------------------------------------------
    ;Widget_Info
    if arg_present(active)         gt 0 then active        = widget_info(self._id, /ACTIVE)
    if arg_present(all_children)   gt 0 then all_children  = widget_info(self._id, /ALL_CHILDREN)
    if arg_present(child)          gt 0 then child         = widget_info(self._id, /CHILD)
    if arg_present(display)        gt 0 then display       = widget_info(self._id, /DISPLAY)
    if arg_present(font_name)      gt 0 then font_name     = widget_info(self._id, /FONT_NAME)
    if arg_present(geometry)       gt 0 then geometry      = widget_info(self._id, /GEOMETRY)
    if arg_present(managed)        gt 0 then managed       = widget_info(self._id, /MANAGED)
    if arg_present(map)            gt 0 then map           = widget_info(self._id, /MAP)
    if arg_present(n_children)     gt 0 then n_children    = widget_info(self._id, /N_CHILDREN)
    if arg_present(name)           gt 0 then name          = widget_info(self._id, /NAME)
    if arg_present(parent)         gt 0 then parent        = widget_info(self._id, /PARENT)
    if arg_present(realized)       gt 0 then realized      = widget_info(self._id, /REALIZED)
    if arg_present(sensitive)      gt 0 then sensitive     = widget_info(self._id, /SENSITIVE)
    if arg_present(sibling)        gt 0 then sibling       = widget_info(self._id, /SIBLING)
    if arg_present(string_size)    gt 0 then string_size   = widget_info(self._id,  STRING_SIZE=string_size)
    if arg_present(system_colors)  gt 0 then system_colors = widget_info(self._id, /SYSTEM_COLORS)
    if arg_present(type)           gt 0 then type          = widget_info(self._id, /TYPE)
    if arg_present(uname)          gt 0 then uname         = widget_info(self._id, /UNAME)
    if arg_present(units)          gt 0 then units         = widget_info(self._id, /UNITS)
    if arg_present(update)         gt 0 then update        = widget_info(self._id, /UPDATE)
    if arg_present(version)        gt 0 then version       = widget_info(self._id, /VERSION)
    if arg_present(visible)        gt 0 then visible       = widget_info(self._id, /VISIBLE)
    
    ;Widget_Control
    if arg_present(window_offset) gt 0 then widget_control, self._id, TLB_GET_OFFSET=window_offset
    if arg_present(window_size)   gt 0 then widget_control, self._id, TLB_GET_SIZE=window_size
    
;---------------------------------------------------------------------
;Are Events On or Off? ///////////////////////////////////////////////
;---------------------------------------------------------------------
    if arg_present(tracking_events)   then tracking_events   = widget_info(self._id, /TRACKING_EVENTS)
    if arg_present(kbrd_focus_events) then kbrd_focus_events = widget_info(self._id, /KBRD_FOCUS_EVENTS)
    
;---------------------------------------------------------------------
;Callback Func/Pro/Method/Object /////////////////////////////////////
;---------------------------------------------------------------------
    if arg_present(event_func)      then event_func      =  self._event_func
    if arg_present(event_pro)       then event_pro       =  self._event_pro
    if arg_present(event_obj)       then event_obj       =  self._event_obj
    if arg_present(func_get_value)  then func_get_value  =  widget_info(self._id, /FUNC_GET_VALUE)
    if arg_present(kill_notify)     then kill_notify     =  self._kill_notify
    if arg_present(notify_realize)  then notify_realize  =  self._notify_realize
    if arg_present(pro_get_value)   then pro_get_value   =  widget_info(self._id, /PRO_GET_VALUE)
    
    if arg_present(tracking_handler)       then tracking_handler       =  self._tracking_handler
    if arg_present(func_get_value_handler) then func_get_value_handler = *self._func_get_value
    if arg_present(kill_notify_handler)    then kill_notify_handler    = *self._kill_notify
    if arg_present(notify_realize_handler) then notify_realize_handler = *self._notify_realize
    if arg_present(pro_set_value_handler)  then pro_set_value_handler  = *self._pro_set_value
end


;+
;   Event handling method for Kill_Notify. If CLEANUP was not provided when XManager was 
;   initiated, then XManager will forward cleanup detail to the procedure specified by
;   KILL_NOTIFY. If KILL_NOTIFY was not given when the object was created, then
;   Kill_Notify events will be directed here.
;
;   So, when the widget is destroyed, this is the fall-back cleanup method. The
;   default action is to destroy the object associated with the widget. If you do not
;   want this to happen, then you must supply your own CLEANUP or KILL_NOTIFY method.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
pro MrWidgetAtom::Kill_Notify, id
   compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif

    ;Destroy the object.
    obj_destroy, self
end


;+
;   Event handling method for Notify Realize.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
pro MrWidgetAtom::Notify_Realize, event
    ;Nothing to do yet.
end


;+
;   Event handling method for Pro_Set_Value.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
pro MrWidgetAtom::Pro_Set_Value, event
    ;Nothing to do yet.
end


;+
;   Event handling method for Tracking Events.
;
; :Private:
;
; :Params:
;       EVENT:              in, optional, type=structure
;                           An event structure returned by the windows manager.
;-
pro MrWidgetAtom::Tracking_Events, event
    ;Nothing to do yet.
end


;+
;   The purpose of this method is to realize the widget.
;
; :Private:
;-
pro MrWidgetAtom::Realize
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif

   ; Check to see if the widget has been realized. If not, realize it.
   if (widget_info (self._id, /REALIZED) eq 0) then widget_control, self._id, /REALIZE
end


;+
;   Set object properties. Complementary to setting object properties, most of the options
;   accessible via Widget_Control and that apply to any widget are able to be set with
;   this method.
;
; :Keywords:
;       CLEAR_EVENTS:       in, optional, type=boolean
;                           If set, any events generated by the widget that have not
;                               yet been processed will be cleared from the event list.
;       DEFAULT_FONTS:      in, optional, type=string
;                           The default font used for widgets that did not specify their
;                               FONT keyword. This keyword is ignored for widgets that
;                               do not support fonts.
;       EVENT_HANDLER:      in, optional, type=struct/string
;                           This keyword replaced the EVENT_PRO and EVENT_FUNC
;                               keywords in Widget_Control and other widget functions.
;                               If a string is provided, it is the name of a procedure
;                               to be called when events are generated. If a structure
;                               is provided, it must have "object" and "method" fields
;                               describing the procedure method to be used as an event
;                               handler::
;                                   {object: object_reference, $
;                                    method: 'callback_method'}
;                               For function event handling, set the `FUNC_HANDLERS`
;                               keyword. If set, all other *_HANDLER keywords are ignored.
;       FUNC_HANDLERS:      in, optional, type=boolean
;                           If set, then `EVENT_HANDLER` (if a string) and all events
;                               handlers whose events are passed through it, are functions,
;                               not procedures.
;       FUNC_GET_VALUE:     in, optional, type=string/structure, default=''
;                           A string specifying the name of a function to be called
;                               when the value of the base is changed. Alternatively,
;                               a structure of the form::
;                                   FUNC_GET_VALUE = {object: objRef, $
;                                                     method: 'Event_Handler'}
;                               where "objRef" is a valid object reference and
;                               "Event_Handler" is a string containing the name of a
;                               function method to be used to handle events. In this
;                               case, 'MrWidgetAtom_Func_Get_Value' will forward event
;                               handling to the specified method.
;       HOURGLASS:          in, optional, type=boolean
;                           If set, the cursor will be turned into an hourglass until the
;                               current event has finished processing.
;       KILL_NOTIFY:        in, optional, type=string/structure, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget dies (see `FUNC_GET_VALUE`).
;       MAP:                in, optional, type=boolean, default=1
;                           Set to 0 to make the widget and its children invisible. Set
;                               to 1 (one) to make them visible again. The widget must
;                               be realized first.
;       NO_COPY:            in, optional, type=boolean, default=0
;                           If set, `UVALUE` will be copied directly into the widget,
;                               leaving the source variable undefined. This prevents
;                               multiple copies of the data from existing.
;       NOTIFY_REALIZE:     in, optional, type=string/structure, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget is realized (see `FUNC_GET_VALUE`).
;       PRO_GET_VALUE:      in, optional, type=string, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget's value is retrieved (see `FUNC_GET_VALUE`).
;       REDRAW:             in, optional, type=boolean
;                           If set to 0, the widget and its children are not updated. If
;                               set to 1 (one), they are. This differs from `UPDATE` in
;                               that `UPDATE` applies to all widgets in the heierarchy.
;                               Equivalent to `UPDATE` for UNIX systems.
;       SENSITIVE:          in, optional, type=boolean
;                           If set, the widget will be sensitive and can receive input.
;                               When insensitive, a widget appears greyed out and does
;                               not generate events.
;       SCR_XSIZE:          in, optional, type=integer
;                           X-size, in units given by `UNITS`, of the widget. Unlike
;                               `XSIZE`, this includes the title bar, menu bar, padding,
;                               and other geometries surrounding the widget.
;       SCR_YSIZE:          in, optional, type=integer
;                           Y-size, in units given by `UNITS`, of the widget. Unlike
;                               `YSIZE`, this includes the title bar, menu bar, padding,
;                               and other geometries surrounding the widget.
;       SHOW:               in, optional, type=integer
;                           Sets the visibility of the widget heierarchy. Choices are::
;                               0 - Send heierarchy to back
;                               1 - Bring heierarchy forward
;       TIMER:              in, optional, type=float
;                           Number of seconds to wait before the timer event arrives.
;       TRACKING_EVENTS:    in, optional, type=boolean
;                           If set, tracking events are enabled.
;       UNAME:              in, optional, type=string, default=''
;                           User-defined name of the widget.
;       UVALUE:             in, optional, type=any
;                           User-defined value of any type to be stored in the object.
;       UDPATE:             in, optional, type=boolean
;                           Enables and disables the widget updates. See Widget_Control
;                               for details.
;       UNITS:              in, optional, type=integer, default=0
;                           The units for measurments. Choices are::
;                               0 - Pixels
;                               1 - Inches
;                               2 - Centimeters
;       WINDOW_TITLE:       in, optional, type=string
;                           String to be placed on the window's title bar.
;       WINDOW_XOFFSET:     in, optional, type=integer
;                           Horizontal offset of the top level base on the screen.
;       WINDOW_YOFFSET:     in, optional, type=integer
;                           Vertical offset of the top level base on the screen.
;       XOFFSET:            in, optional, type=integer
;                           Horizontal offset of the widget.
;       XSIZE:              in, optional, type=integer
;                           Horizontal size of the widget. Unlike `SCR_XSIZE`, this is
;                               the the size of the widget and no more.
;       YOFFSET:            in, optional, type=integer
;                           Vertical offset of the widget.
;       YSIZE:              in, optional, type=integer
;                           Vertical size of the widget. Unlike `SCR_YSIZE`, this is
;                               the the size of the widget and no more.
;-
pro MrWidgetAtom::SetProperty, $
 ;Widget_Control Options
 CLEAR_EVENTS=clear_events, $
 DEFAULT_FONTS=default_fonts, $
 FUNC_HANDLERS=func_handlers, $
 HOURGLASS=hourglass, $
 MAP=map, $
 NO_COPY = no_copy, $
 REDRAW=redraw, $
 SENSITIVE=sensitive, $
 SCR_XSIZE=scr_xsize, $
 SCR_YSIZE=scr_ysize, $
 SHOW=show, $
 TIMER=timer, $
 UNAME=uname, $
 UNITS=units, $
 UVALUE=uvalue, $
 UPDATE=update, $
 WINDOW_TITLE=window_title, $
 WINDOW_XOFFSET=window_xoffset, $
 WINDOW_YOFFSET=window_yoffset, $
 XOFFSET=xoffset, $
 XSIZE=xsize, $
 YOFFSET=yoffset, $
 YSIZE=ysize, $
 
 ;Turn Events On or Off
 TRACKING_EVENTS = tracking_events, $
 
 ;Callback Pro/Func/Method
 EVENT_PRO        = event_pro, $
 EVENT_FUNC       = event_func, $
 EVENT_OBJ        = event_obj, $
 FUNC_GET_VALUE   = func_get_value, $
 KILL_NOTIFY      = kill_notify, $
 NOTIFY_REALIZE   = notify_realize, $
 PRO_SET_VALUE    = pro_get_value, $
 TRACKING_HANDLER = tracking_handler
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif

;---------------------------------------------------------------------
;Widget Control Options //////////////////////////////////////////////
;---------------------------------------------------------------------
    
    if n_elements(clear_events)  gt 0 then widget_control, self._id, CLEAR_EVENTS  = keyword_set(clear_events)
    if n_elements(default_fonts) gt 0 then widget_control,           DEFAULT_FONTS = default_fonts
    if n_elements(hourglass)     gt 0 then widget_control,           HOURGLASS     = keyword_set(hourglass)
    if n_elements(map)           gt 0 then widget_control, self._id, MAP           = keyword_set(map)
    if n_elements(redraw)        gt 0 then widget_control, self._id, REDRAW        = keyword_set(redraw)
    if n_elements(sensitive)     gt 0 then widget_control, self._id, SENSITIVE     = sensitive
    if n_elements(scr_xsize)     gt 0 then widget_control, self._id, SCR_XSIZE     = scr_xsize
    if n_elements(scr_ysize)     gt 0 then widget_control, self._id, SCR_YSIZE     = scr_ysize
    if n_elements(show)          gt 0 then widget_control, self._id, SHOW          = keyword_set(show)
    if n_elements(uname)         gt 0 then widget_control, self._id, SET_UNAME     = uname
    if n_elements(units)         gt 0 then widget_control, self._id, UNITS         = units
    if n_elements(update)        gt 0 then widget_control, self._id, UPDATE        = keyword_set(update)
    if n_elements(xoffset)       gt 0 then widget_control, self._id, XOFFSET       = xoffset
    if n_elements(xsize)         gt 0 then widget_control, self._id, XSIZE         = xsize
    if n_elements(yoffset)       gt 0 then widget_control, self._id, YOFFSET       = yoffset
    if n_elements(ysize)         gt 0 then widget_control, self._id, YSIZE         = ysize

;---------------------------------------------------------------------
;Turn Events On or Off ///////////////////////////////////////////////
;---------------------------------------------------------------------
    if n_elements(tracking_events) gt 0 then widget_control, self._id, TRACKING_EVENTS=keyword_set(tracking_events)

;---------------------------------------------------------------------
;Callback Func/Pro/Method/Object /////////////////////////////////////
;---------------------------------------------------------------------
    ;EVENT_PRO takes precedence over EVENT_FUNC
    if n_elements(event_func)       gt 0 then self -> _Set_Event_Func, event_func
    if n_elements(event_pro)        gt 0 then self -> _Set_Event_Pro, event_pro
    if n_elements(event_obj)        gt 0 then self._event_obj        = event_obj
    if n_elements(tracking_handler) gt 0 then self._tracking_handler = tracking_handler  

    ;FUNC_GET_VALUE
    if n_elements(func_get_value) gt 0 then begin
        case size(func_get_value, /TNAME) of
            'STRUCT': begin
                test = {MrEventHandler}
                struct_assign, func_get_value, test
                *self._func_get_value = test
                widget_control, self._id, FUNC_GET_VALUE='MrWidgetAtom_Func_Get_Value'
            endcase
            'STRING': begin
                widget_control, self_id, FUNC_GET_VALUE=func_get_value
                *self._func_get_value = func_get_value
            endcase
            else: message, 'FUNC_GET_VALUE must be a string or structure.'
        endcase
    endif
    
    ;KILL_NOTIFY
    if n_elements(kill_notify) gt 0 then begin
        case size(kill_notify, /TNAME) of
            'STRUCT': begin
                test = {MrEventHandler}
                struct_assign, kill_notify, test
                *self._kill_notify = test
                widget_control, self._id, KILL_NOTIFY='MrWidgetAtom_Kill_Notify'
            endcase
            'STRING': begin
                widget_control, self_id, KILL_NOTIFY=kill_notify
                *self._kill_notify = kill_notify
            endcase
            else: message, 'KILL_NOTIFY must be a string or structure.'
        endcase
    endif
    
    ;NOTIFY_REALIZE
    if n_elements(notify_realize) gt 0 then begin
        case size(notify_realize, /TNAME) of
            'STRUCT': begin
                test = {MrEventHandler}
                struct_assign, notify_realize, test
                *self._notify_realize = test
                widget_control, self._id, NOTIFY_REALIZE='MrWidgetAtom_Notify_Realize'
            endcase
            'STRING': begin
                widget_control, self_id, NOTIFY_REALIZE=notify_realize
                *self._notify_realize = notify_realize
            endcase
            else: message, 'NOTIFY_REALIZE must be a string or structure.'
        endcase
    endif
    
    ;PRO_SET_VALUE
    if n_elements(pro_set_value) gt 0 then begin
        case size(pro_set_value, /TNAME) of
            'STRUCT': begin
                test = {MrEventHandler}
                struct_assign, pro_set_value, test
                *self._pro_set_value = test
                widget_control, self._id, PRO_SET_VALUE='MrWidgetAtom_Pro_Set_Value'
            endcase
            'STRING': begin
                widget_control, self_id, PRO_SET_VALUE=pro_set_value
                *self._pro_set_value = pro_set_value
            endcase
            else: message, 'PRO_SET_VALUE must be a string or structure.'
        endcase
    endif
end


;+
;   The purpose of this method is to set the Event_Pro callback procedure.
;
; :Private:
;
; :Params:
;       EVENT_PRO:          in, required, type=string
;                           Name of the callback procedure to be used when events are
;                               generated.
;-
pro MrWidgetAtom::_Set_Event_Pro, event_pro
    compile_opt strictarr
    on_error, 2

    ;Set the Callback Procedure
    if event_pro eq '' $
        then widget_control, self._id, EVENT_PRO='' $
        else widget_control, self._id, EVENT_PRO=obj_class(self) + '_Event_Pro'
    
    ;Setting EVENT_PRO will automatically set EVENT_FUNC=''
    self._event_pro = event_pro
    self._event_func = ''
end


;+
;   The purpose of this method is to set the Event_Func callback function.
;
; :Private:
;
; :Params:
;       EVENT_FUNC:         in, required, type=string
;                           Name of the callback function to be used when events are
;                               generated.
;-
pro MrWidgetAtom::_Set_Event_Func, event_func
    compile_opt strictarr
    on_error, 2
    
    ;EVENT_FUNC
    if event_func eq '' $
        then widget_control, self._id, EVENT_FUNC='' $
        else widget_control, self._id, EVENT_FUNC=obj_class(self) + '_Event_Func'
    
    ;Setting EVENT_FUNC will automatically set EVENT_PRO=''
    self._event_func = event_func
    self._event_pro = ''
end


;+
;   Clean up after the widget is destroyed.
;
; :Private:
;-
pro MrWidgetAtom::Cleanup
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return
    endif
    
    ;Free the user value
    ptr_free, self.uvalue

    ;If the widget is still valid, destroy it.
    ;   - We need the Kill_Notify event handler.
    if widget_info(self._id, /VALID_ID) then widget_control, self._id, /DESTROY
    
    ;Free event handlers (but do not destroy callback objects)
    ptr_free, self._func_get_value
    ptr_free, self._kill_notify
    ptr_free, self._notify_realize
    ptr_free, self._pro_set_value
end


;+
;   This is the DRAWWIDGET object class initialization method
;
; :Params:
;       PARENT:             in, optional, type=long/object
;                           A widget ID or the object reference of a MrWidget routine
;                               that is to be used as the parent widget.
;
; :Keywords:
;       EVENT_FUNC:         in, optional, type=string, default=''
;                           Event handling function to be called when an event is received
;                               from XManager. If set, all of the *_HANDLER keywords are
;                               ignored.
;       EVENT_PRO:          in, optional, type=string, default=''
;                           Event handling procedure to be called when an event is received
;                               from XManager. If set, all of the *_HANDLER keywords are
;                               ignored. This takes precedence over `EVENT_FUNC`.
;       EVENT_OBJ:          in, optional, type=string, default=obj_new()
;                           Object to be used as an event handler class. If provided, then
;                               `EVENT_PRO`, `EVENT_FUNC` and all of the *_HANDLER
;                               procedural callback routines will be interpreted as
;                               methods of the `EVENT_OBJ` class.
;       FUNC_GET_VALUE:     in, optional, type=string/structure, default=''
;                           A string specifying the name of a function to be called
;                               when the value of the base is changed. Alternatively,
;                               a structure of the form::
;                                   FUNC_GET_VALUE = {object: objRef, $
;                                                     method: 'Event_Handler'}
;                               where "objRef" is a valid object reference and
;                               "Event_Handler" is a string containing the name of a
;                               function method to be used to handle events. In this
;                               case, 'MrWidgetAtom_Func_Get_Value' will forward event
;                               handling to the specified method.
;       KILL_NOTIFY:        in, optional, type=string/structure, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget dies (see `FUNC_GET_VALUE`).
;       NO_COPY:            in, optional, type=boolean, default=0
;                           If set, `UVALUE` will be copied directly into the widget,
;                               leaving the source variable undefined. This prevents
;                               multiple copies of the data from existing.
;       NOTIFY_REALIZE:     in, optional, type=string/structure, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget is realized (see `FUNC_GET_VALUE`).
;       PRO_GET_VALUE:      in, optional, type=string, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when the widget's value is retrieved (see `FUNC_GET_VALUE`).
;       SENSITIVE:          in, optional, type=boolean, default=1
;                           If set, the widget will be sensitive and can receive input.
;                               When insensitive, a widget appears greyed out and does
;                               not generate events.
;       TRACKING_EVENTS:    in, optional, type=boolean, default=0
;                           If set, tracking events are enabled.
;       TRACKING_HANDLER:   in, optional, type=string/structure, default=''
;                           A string containing the name of a procedure or a structure
;                               containing an object and its method to be called
;                               when a tracking event occurs (see `FUNC_GET_VALUE`).
;       UNAME:              in, optional, type=string, default=''
;                           User-defined name of the widget.
;       UVALUE:             in, optional, type=any
;                           User-defined value of any type to be stored in the object.
;                               The UValue of the widget is required by MrWidgetAtom and
;                               its subclasses and should not be changed. Instead, use
;                               the Get/SetProperty methods to access the object's UVALUE.
;-
function MrWidgetAtom::init, parent, $
 ID        = id, $
 NO_COPY   = no_copy, $
 SENSITIVE = sensitive, $
 UNAME     = uname, $
 UVALUE    = uvalue, $
 ;Callbacks
 EVENT_FUNC       = event_func, $
 EVENT_PRO        = event_pro, $
 EVENT_OBJ        = event_obj, $
 FUNC_GET_VALUE   = func_get_value, $
 KILL_NOTIFY      = kill_notify, $
 NOTIFY_REALIZE   = notify_realize, $
 PRO_SET_VALUE    = pro_set_value, $
 TRACKING_EVENTS  = tracking_events, $
 TRACKING_HANDLER = tracking_handler
    compile_opt strictarr
    
    ;Error handling
    catch, the_error
    if the_error ne 0 then begin
        catch, /cancel
        void = cgErrorMsg()
        return, 0
    endif
    
    
    ;Callback Func/Pro/Methods
    if n_elements(event_pro) + n_elements(event_func) eq 0 then event_pro = obj_class(self) + '_Event_Pro'
    if n_elements(func_get_value)   eq 0 then func_get_value   = {object: self, method: 'Func_Get_Value'}
    if n_elements(kill_notify)      eq 0 then kill_notify      = {object: self, method: 'Kill_Notify'}
    if n_elements(notify_realize)   eq 0 then notify_realize   = {object: self, method: 'Notify_Realize'}
    if n_elements(pro_set_value)    eq 0 then pro_set_value    = {object: self, method: 'Pro_Set_Value'}
    
    ;Allocate Heap
    self._func_get_value   = ptr_new(/ALLOCATE_HEAP)
    self._kill_notify      = ptr_new(/ALLOCATE_HEAP)
    self._notify_realize   = ptr_new(/ALLOCATE_HEAP)
    self._pro_set_value    = ptr_new(/ALLOCATE_HEAP)
    
;---------------------------------------------------------------------
;Set Object Properties ///////////////////////////////////////////////
;---------------------------------------------------------------------
    
    ;Set Object Properties
    self -> SetProperty, UNAME=uname, $
                         UVALUE=uvalue, $
                         SENSITIVE=sensitive, $
                         FUNC_HANDLERS=func_handlers, $
                         ;Callbacks
                         EVENT_FUNC=event_func, $
                         EVENT_PRO=event_pro, $
                         EVENT_OBJ=event_obj, $
                         KILL_NOTIFY=kill_notify, $
                         NOTIFY_REALIZE=notify_realize, $
                         PRO_SET_VALUE=pro_set_value, $
                         TRACKING_EVENTS=tracking_events, $
                         TRACKING_HANDLER=tracking_handler

    ;Store the object as the uservalue
    Widget_Control, self._id, SET_UVALUE=self
    if arg_present(id) then id = self._id    
    
    return, 1
end



;+
;   The class definition statement.
;
; :Params:
;       CLASS:          out, optional, type=structure
;                       The class definition structure.
;
; :Fields:
;       _ID:                    Widget ID of the top level base
;       _EVENT_FUNC:            Event handling function for widget events.
;       _EVENT_PRO:             Event handling procedure for widget events.
;       _EVENT_OBJ:             Event handling object for widget events.
;       _FUNC_GET_VALUE:        Object and function method to handle get value events.
;       _PRO_SET_VALUE:         Object and procedure method to handle get value events.
;       UVALUE:                 The user value of the widget object.
;-
pro MrWidgetAtom__define, class
    
    class = { MrWidgetAtom, $
              inherits IDL_Object, $
              _id:               0L, $
              _event_func:       '', $
              _event_pro:        '', $
              _event_obj:        obj_new(), $
              _func_get_value:   ptr_new(), $
              _kill_notify:      ptr_new(), $
              _notify_realize:   ptr_new(), $
              _pro_set_value:    ptr_new(), $
              _tracking_handler: '', $
              uvalue:            ptr_new() $
            }
end